package com.atguigu.gulimall.cart.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.common.constant.CartConstant;
import com.atguigu.common.to.product.SkuInfoTo;
import com.atguigu.common.utils.R;
import com.atguigu.gulimall.cart.feign.ProductFeignService;
import com.atguigu.gulimall.cart.interceptor.CartInterceptor;
import com.atguigu.gulimall.cart.service.CartService;
import com.atguigu.gulimall.cart.to.UserInfoTo;
import com.atguigu.gulimall.cart.vo.CartItemVo;
import com.atguigu.gulimall.cart.vo.CartVo;
import com.fasterxml.jackson.core.type.TypeReference;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    @Resource
    private ThreadPoolTaskExecutor taskExecutor;

    @Resource
    private ProductFeignService productFeignService;

    @Override
    public CartItemVo addToCart(Long skuId, Integer num) {
        BoundHashOperations<String, String, String> op = getHashOp();

        String cartItemStr = op.get(skuId.toString());
        if (!StringUtils.isEmpty(cartItemStr)) {
            // 说明缓存中有数据,直接操作缓存
            CartItemVo vo = JSON.parseObject(cartItemStr, CartItemVo.class);
            vo.setCount(vo.getCount() + num);
            op.put(skuId.toString(), JSON.toJSONString(vo));
            return vo;
        }

        CartItemVo vo = new CartItemVo();

        // 根据skuId 查询sku 信息
        CompletableFuture<Void> skuInfoTask = CompletableFuture.runAsync(() -> {
            R r = productFeignService.skuInfo(skuId);
            if (r.isOk()) {
                SkuInfoTo skuInfo = r.getData("skuInfo", new TypeReference<SkuInfoTo>() {
                });
                vo.setSkuId(skuId);
                vo.setChecked(true);
                vo.setTitle(skuInfo.getSkuTitle());
                vo.setImage(skuInfo.getSkuDefaultImg());
                vo.setPrice(skuInfo.getPrice());
                vo.setCount(num);
            }
        }, taskExecutor);

        // 根据skuId 查询属性信息
        CompletableFuture<Void> skuAttrsTask = CompletableFuture.runAsync(() -> {
            R r = productFeignService.getSkuSaleAttrStringList(skuId);
            if (r.isOk()) {
                List<String> data = r.getData(new TypeReference<List<String>>() {
                });
                vo.setSkuAttrs(data);
            }
        }, taskExecutor);

        // 阻塞等待远程调用完成
        CompletableFuture.allOf(skuInfoTask, skuAttrsTask).join();

        op.put(skuId.toString(), JSON.toJSONString(vo));
        return vo;
    }

    @Override
    public CartItemVo getCartItem(Long skuId) {
        BoundHashOperations<String, String, String> op = getHashOp();
        String data = op.get(skuId.toString());
        return JSON.parseObject(data, CartItemVo.class);
    }

    @Override
    public CartVo getCart() {
        CartVo cartVo = new CartVo();
        BoundHashOperations<String, String, String> noLoginOp = getHashOp(true);
        BoundHashOperations<String, String, String> loginOp = getHashOp(false);
        if (isLogin()) {
            // 登录的话合并购物车
            // 判断是否存在临时购物车数据 获取临时购物车数据,合并到登录购物车中
            List<CartItemVo> tempCartItems = getAllCartItems(noLoginOp);
            if (tempCartItems != null && !tempCartItems.isEmpty()) {
                tempCartItems.forEach(item -> addToCart(item.getSkuId(), item.getCount()));
            }
            List<CartItemVo> allCartItems = getAllCartItems(loginOp);
            cartVo.setItems(allCartItems);
            clearTempCart();
        } else {
            List<CartItemVo> allCartItems = getAllCartItems(noLoginOp);
            cartVo.setItems(allCartItems);
        }

        return cartVo;
    }

    @Override
    public void clearTempCart() {
        stringRedisTemplate.delete(getCartKey(true));
    }

    @Override
    public void checkItem(Long skuId, Integer checked) {
        CartItemVo cartItem = getCartItem(skuId);
        cartItem.setChecked(checked == 1);
        getHashOp().put(skuId.toString(), JSON.toJSONString(cartItem));
    }

    @Override
    public void changeNumItem(Long skuId, Integer num) {
        CartItemVo cartItem = getCartItem(skuId);
        cartItem.setCount(num);
        getHashOp().put(skuId.toString(), JSON.toJSONString(cartItem));
    }

    @Override
    public void deleteItem(Long skuId) {
        getHashOp().delete(skuId.toString());
    }

    @Override
    public List<CartItemVo> cartItemsByMemberId(Long memberId) {
//        String cartKey = CartConstant.CART_CACHE_PREFIX + memberId;
//        List<CartItemVo> allCartItems = getAllCartItems(cartKey);
        List<CartItemVo> allCartItems = getAllCartItems(getHashOp());
        if (allCartItems != null && !allCartItems.isEmpty()) {
            return allCartItems.stream()
                    .filter(CartItemVo::getChecked)
                    .peek(item -> {
                        // 调用远程服务获取价格信息
                        R r = productFeignService.skuInfo(item.getSkuId());
                        if (r.isOk()) {
                            SkuInfoTo skuInfo = r.getData("skuInfo", new TypeReference<SkuInfoTo>() {
                            });
                            item.setPrice(skuInfo.getPrice());
                        }
                    }).collect(Collectors.toList());
        }
        return null;
    }


    private BoundHashOperations<String, String, String> getHashOp() {
        UserInfoTo info = CartInterceptor.getUserInfoTo();
        String cacheKey;
        if (info.getUserId() != null) {
            cacheKey = CartConstant.CART_CACHE_PREFIX + info.getUserId();
        } else {
            cacheKey = CartConstant.CART_CACHE_PREFIX + info.getUserKey();
        }
        return stringRedisTemplate.boundHashOps(cacheKey);
    }

    private BoundHashOperations<String, String, String> getHashOp(boolean isUserKey) {
        return stringRedisTemplate.boundHashOps(getCartKey(isUserKey));
    }

    private BoundHashOperations<String, String, String> getHashOp(String cartKey) {
        return stringRedisTemplate.boundHashOps(cartKey);
    }

    private String getCartKey(boolean isUserKey) {
        UserInfoTo info = CartInterceptor.getUserInfoTo();
        String cacheKey;
        if (!isUserKey) {
            cacheKey = CartConstant.CART_CACHE_PREFIX + info.getUserId();
        } else {
            cacheKey = CartConstant.CART_CACHE_PREFIX + info.getUserKey();
        }
        return cacheKey;
    }

    private boolean isLogin() {
        UserInfoTo info = CartInterceptor.getUserInfoTo();
        return info.getUserId() != null;
    }


    private List<CartItemVo> getAllCartItems(BoundHashOperations<String, String, String> op) {
        List<String> values = op.values();
        if (values == null || values.isEmpty()) {
            return null;
        }
        return values.stream().map(item -> JSON.parseObject(item, CartItemVo.class)).collect(Collectors.toList());
    }

    private List<CartItemVo> getAllCartItems(String cartKey) {
        List<String> values = getHashOp(cartKey).values();
        if (values == null || values.isEmpty()) {
            return null;
        }
        return values.stream().map(item -> JSON.parseObject(item, CartItemVo.class)).collect(Collectors.toList());
    }
}
